home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / fileutil / giftrans.tar.gz / giftrans.tar / giftrans / giftrans.c < prev    next >
C/C++ Source or Header  |  1996-09-03  |  27KB  |  983 lines

  1. /*
  2. ** GIFtrans v1.12.2
  3. **
  4. ** Convert any GIF file into a GIF89a
  5. ** Allows for setting the transparent or background color, changing colors,
  6. ** adding or removing comments. Also code to analyze GIF contents.
  7. **
  8. ** Copyright (C) 24.2.94 by Andreas Ley <ley@rz.uni-karlsruhe.de>
  9. **
  10. ** This program is free software; you can redistribute it and/or modify
  11. ** it under the terms of the GNU General Public License as published by
  12. ** the Free Software Foundation; either version 2 of the License, or
  13. ** (at your option) any later version.
  14. **
  15. ** This program is distributed in the hope that it will be useful,
  16. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. ** GNU General Public License for more details.
  19. **
  20. ** You should have received a copy of the GNU General Public License
  21. ** along with this program; if not, write to the Free Software
  22. ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23. **
  24. ** This program has been tested on a HP9000/715 with HP-UX A.09.05
  25. ** In this environment, neither lint -u nor gcc -Wall produce any messages.
  26. ** It has also been compiled on AIX 3.2 and Solaris 2.3.
  27. ** If you encounter any errors or need to make any changes to port it
  28. ** to another platform, please contact me.
  29. **
  30. ** Known bugs:
  31. **    -B flag won't work if there's an Extension between the Global Color
  32. **    Table and the Image Descriptor (or Graphic Control Extension). If -V
  33. **    has been specified, a Warning Message will be displayed.
  34. **    Will be fixed in 2.0 (if ever)
  35. **    -D option may output changed data instead of original data, use
  36. **    with caution, best only with then -L option.
  37. **
  38. ** Version history
  39. **
  40. ** Version 1.12.2 - 11.4.96
  41. **    Changed to GNU copyright
  42. **
  43. ** Version 1.12.1 - 9.2.96
  44. **    Fix for multi-word color names.
  45. **
  46. ** Version 1.12 - 17.2.95
  47. **    Incorporated dumpcomment by omerzu@quantum.de (Thomas Omerzu)
  48. **    Outputs original version if newer than GIF89a.
  49. **
  50. ** Version 1.11.2 - 14.12.94
  51. **    Incorporated OS/2 port by k.rusch@ieee.org (Klaus Johannes Rusch)
  52. **    Different rgb.txt file for OS/2, setmode replaced by freopen for
  53. **    OS/2 (SAA C) 
  54. **
  55. ** Version 1.11.1 - 11.8.94
  56. **    Allows for use of the -g option without the -B option.
  57. **
  58. ** Version 1.11 - 21.7.94
  59. **    Moved Plain Text Extension to the Extensions section where it belongs.
  60. **    Accept Unknown Extension Labels.
  61. **    Incorporated MS-DOS port by enzo@hk.net (Enzo Michelangeli).
  62. **    Added -o and -e options to redirect stdout and stderr.
  63. **    Added -D debug flag.
  64. **
  65. ** Version 1.10.2 - 22.6.94
  66. **    Support for -DRGBTXT flag.
  67. **
  68. ** Version 1.10.1 - 21.6.94
  69. **    Different rgb.txt file FreeBSD/386BSD.
  70. **
  71. ** Version 1.10 - 19.6.94
  72. **    Added -g option to change a color in the global color table.
  73. **    Added -B option to change the color for the transparent color index.
  74. **
  75. ** Version 1.9.1 - 7.6.94
  76. **    Different rgb.txt files for X11 and Open Windows.
  77. **
  78. ** Version 1.9 - 1.6.94
  79. **    Fixed a bug which caused color names to be rejected.
  80. **
  81. ** Version 1.8 - 30.5.94
  82. **    Accept #rrggbb style arguments.
  83. **    Do nothing if rgb-color not found in GIF.
  84. **
  85. ** Version 1.7 - 16.5.94
  86. **    Added -l option to only list the color table.
  87. **    Added -L option for verbose output without creating a gif.
  88. **    Added -b option to change the background color index.
  89. **    Display all matching color names for color table entries.
  90. **    Fixed a bug which caused bad color names if rgb.txt starts with
  91. **        whitespace.
  92. **    Doesn't use strdup anymore.
  93. **    Fixed =& bug on dec machines.
  94. **
  95. ** Version 1.6 - 5.4.94
  96. **    Added color names recognition.
  97. **
  98. ** Version 1.5 - 15.3.94
  99. **    Added basic verbose output to analyze GIFs.
  100. **
  101. ** Version 1.4 - 8.3.94
  102. **    Fixed off-by-one bug in Local Color table code.
  103. **    Added -c and -C options to add or remove a comment.
  104. **    Transparency is no longer the default.
  105. **
  106. ** Thanx for bug reports, ideas and fixes to
  107. **    patricka@cs.kun.nl (Patrick Atoon)
  108. **    wes@msc.edu (Wes Barris)
  109. **    pmfitzge@ingr.com (Patrick M. Fitzgerald)
  110. **    hoesel@chem.rug.nl (Frans van Hoesel)
  111. **    boardman@jerry.sal.wisc.edu (Dan Boardman)
  112. **    krweiss@chip.ucdavis.edu (Ken Weiss)
  113. **    chuck.musciano@harris.com (Chuck Musciano)
  114. **    heycke@camis.stanford.edu (Torsten Heycke)
  115. **    claw@spacsun.rice.edu (Colin Law)
  116. **    jwalker@eos.ncsu.edu (Joseph C. Walker)
  117. **    Bjorn.Borud@alkymi.unit.no (Bjorn Borud)
  118. **    Christopher.Vance@adfa.oz.au (CJS Vance)
  119. **    pederl@norway.hp.com (Peder Langlo)
  120. **    I.Rutson@bradford.ac.uk (Ian Rutson)
  121. **    Nicolas.Pioch@enst.fr (Nicolas Pioch)
  122. **    john@charles.CS.UNLV.EDU (John Kilburg)
  123. **    enzo@hk.net (Enzo Michelangeli)
  124. **    twv@hpwtwe0.cup.hp.com (Terry von Gease)
  125. **    k.rusch@ieee.org (Klaus Johannes Rusch)
  126. **    omerzu@quantum.de (Thomas Omerzu)
  127. **    Willem.Vermin@sara.nl (Willem Vermin)
  128. **    wjones@tc.fluke.COM (Warren Jones)
  129. **
  130. ** Original distribution site is
  131. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.c
  132. ** A man-page by knordlun@fltxa.helsinki.fi (Kai Nordlund) is at
  133. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.1
  134. ** An online version by taylor@intuitive.com (Dave Taylor) is at
  135. **       http://www.intuitive.com/coolweb/Addons/giftrans-doc.html
  136. ** To compile for MS-DOS or OS/2, you need getopt:
  137. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/getopt.c
  138. ** MS-DOS executable can be found at
  139. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.exe
  140. ** OS/2 executable can be found at
  141. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.os2.exe
  142. ** A template rgb.txt for use with the MS-DOS version can be found at
  143. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/rgb.txt
  144. ** Additional info can be found on
  145. **    http://melmac.corp.harris.com/transparent_images.html
  146. ** The GIF file format is documented in
  147. **    ftp://ftp.uu.net/doc/literary/obi/Standards/Graphics/Formats/gif89a.doc.Z
  148. */
  149.  
  150. #define    X11        /* When using X Window System */
  151. #undef    OPENWIN        /* When using Open Windows */
  152. #undef    X386        /* When using XFree86 with FreeBSD/386BSD */
  153. #undef    OS2        /* When using IBM C/C++ 2.0 */
  154. #ifndef    MSDOS    /* required for TurboC 1.0 */
  155. #undef    MSDOS        /* When using Borland C (maybe MSC too) */
  156. #endif
  157.  
  158. #ifndef OS2_OR_MSDOS
  159. #ifdef OS2
  160. #define OS2_OR_MSDOS
  161. #endif /* OS2 */
  162. #ifdef MSDOS
  163. #define OS2_OR_MSDOS
  164. #endif /* MSDOS */
  165. #endif /* OS2_OR_MSDOS */
  166.  
  167. char copyright[] = "@(#)Copyright (C) 1994 by Andreas Ley (ley@rz.uni-karlsruhe.de)";
  168. char sccsid[] = "@(#)GIFtrans v1.12.2 - Transpose GIF files";
  169.  
  170. #ifndef RGBTXT
  171. #ifdef X11
  172. #define    RGBTXT    "/usr/lib/X11/rgb.txt"
  173. #else /* X11 */
  174. #ifdef OPENWIN
  175. #define    RGBTXT    "/usr/openwin/lib/rgb.txt"
  176. #else /* OPENWIN */
  177. #ifdef X386
  178. #define    RGBTXT    "/usr/X386/lib/X11/rgb.txt"
  179. #else /* X386 */
  180. #ifdef OS2_OR_MSDOS
  181. #define    RGBTXT    "rgb.txt"
  182. #else /* OS2_OR_MSDOS */
  183. #define    RGBTXT    "";
  184. #endif /* OS2_OR_MSDOS */
  185. #endif /* X386 */
  186. #endif /* OPENWIN */
  187. #endif /* X11 */
  188. #endif /* RGBTXT */
  189.  
  190. #include <stdlib.h>
  191. #include <stdio.h>
  192. #include <string.h>
  193. #include <errno.h>
  194. #ifndef OS2_OR_MSDOS
  195. #include <unistd.h>
  196. #include <ctype.h>
  197. #include <sys/param.h>
  198. #else /* OS2_OR_MSDOS */
  199. #include <fcntl.h>
  200. #ifdef OS2
  201. #include <io.h>
  202. #endif /* OS2 */
  203. #include "getopt.c"
  204. #endif /* OS2_OR_MSDOS */
  205.  
  206. #ifndef MAXPATHLEN
  207. #define MAXPATHLEN 256
  208. #endif /* MAXPATHLEN */
  209.  
  210. #ifndef FALSE
  211. #define    FALSE    (0)        /* This is the naked Truth */
  212. #define    TRUE    (1)        /* and this is the Light */
  213. #endif
  214.  
  215. #define    SUCCESS    (0)
  216. #define    FAILURE    (1)
  217.  
  218. struct entry {
  219.     struct entry    *next;
  220.     char        *name;
  221.     int        red;
  222.     int        green;
  223.     int        blue;
  224.     } *root;
  225.  
  226. #define    NONE    (-1)
  227. #define    OTHER    (-2)
  228. #define    RGB    (-3)
  229.  
  230. struct color {
  231.     int        index;
  232.     int        red;
  233.     int        green;
  234.     int        blue;
  235.     } bc,tc,tn,go,gn;
  236.  
  237. static char    *image,*comment;
  238. static int    skipcomment,list,verbose,output,debug;
  239. static long int    pos;
  240.  
  241. static char    rgbtxt[] = RGBTXT, *rgb = rgbtxt;
  242. static char    true[] = "True";
  243. static char    false[] = "False";
  244.  
  245. #define    readword(buffer)    ((buffer)[0]+256*(buffer)[1])
  246. #define    readflag(buffer)    ((buffer)?true:false)
  247. #define    hex(c)            ('a'<=(c)&&(c)<='z'?(c)-'a'+10:'A'<=(c)&&(c)<='Z'?(c)-'A'+10:(c)-'0')
  248.  
  249.  
  250. void dump(adr,data,len)
  251. long int    adr;
  252. unsigned char    *data;
  253. size_t        len;
  254. {
  255.     int    i;
  256.  
  257.     while (len>0) {
  258.         (void)fprintf(stderr,"%08lx:%*s",adr,(int)((adr%16)*3+(adr%16>8?1:0)),"");
  259.         for (i=adr%16;i<16&&len>0;i++,adr++,data++,len--)
  260.             (void)fprintf(stderr,"%s%02x",i==8?"  ":" ",*data);
  261.         (void)fprintf(stderr,"\n");
  262.     }
  263. }
  264.  
  265.  
  266.  
  267. void writedata(dest,data,len)
  268. FILE        *dest;
  269. unsigned char    *data;
  270. size_t        len;
  271. {
  272.     unsigned char    size;
  273.  
  274.     while (len) {
  275.         size=len<256?len:255;
  276.         (void)fwrite((void *)&size,1,1,dest);
  277.         (void)fwrite((void *)data,(size_t)size,1,dest);
  278.         data+=size;
  279.         len-=size;
  280.     }
  281.     size=0;
  282.     (void)fwrite((void *)&size,1,1,dest);
  283. }
  284.  
  285.  
  286. void skipdata(src)
  287. FILE    *src;
  288. {
  289.     unsigned char    size,buffer[256];
  290.  
  291.     do {
  292.         pos=ftell(src);
  293.         (void)fread((void *)&size,1,1,src);
  294.         if (debug)
  295.             dump(pos,&size,1);
  296.         if (debug) {
  297.             pos=ftell(src);
  298.             (void)fread((void *)buffer,(size_t)size,1,src);
  299.             dump(pos,buffer,(size_t)size);
  300.         }
  301.         else
  302.             (void)fseek(src,(long int)size,SEEK_CUR);
  303.     } while (!feof(src)&&size>0);
  304. }
  305.  
  306.  
  307. void transblock(src,dest)
  308. FILE    *src;
  309. FILE    *dest;
  310. {
  311.     unsigned char    size,buffer[256];
  312.  
  313.     pos=ftell(src);
  314.     (void)fread((void *)&size,1,1,src);
  315.     if (debug)
  316.         dump(pos,&size,1);
  317.     if (output)
  318.         (void)fwrite((void *)&size,1,1,dest);
  319.     pos=ftell(src);
  320.     (void)fread((void *)buffer,(size_t)size,1,src);
  321.     if (debug)
  322.         dump(pos,buffer,(size_t)size);
  323.     if (output)
  324.         (void)fwrite((void *)buffer,(size_t)size,1,dest);
  325. }
  326.  
  327.  
  328. void dumpcomment(src)
  329. FILE    *src;
  330. {
  331.     unsigned char    size,buffer[256];
  332.     size_t i;
  333.  
  334.     pos=ftell(src);
  335.     (void)fread((void *)&size,1,1,src);
  336.     if (debug)
  337.         dump(pos,&size,1);
  338.     (void)fread((void *)buffer,(size_t)size,1,src);
  339.     if (debug)
  340.         dump(pos+1,buffer,(size_t)size);
  341.     for (i=0; i<(size_t)size; i++)
  342.     {
  343.         if (i%60==0)
  344.             (void)putc('\t',stderr);
  345.         if (isprint(buffer[i]))
  346.             (void)putc(buffer[i],stderr);
  347.         else
  348.             (void)fprintf(stderr,"\\%03o",buffer[i]);
  349.         if (i%60==59)
  350.             (void)putc('\n',stderr);
  351.     }
  352.     if (i%60)
  353.         (void)putc('\n',stderr);
  354.     (void)fseek(src,(long int)pos,SEEK_SET);
  355. }
  356.  
  357.  
  358. void transdata(src,dest)
  359. FILE    *src;
  360. FILE    *dest;
  361. {
  362.     unsigned char    size,buffer[256];
  363.  
  364.     do {
  365.         pos=ftell(src);
  366.         (void)fread((void *)&size,1,1,src);
  367.         if (debug)
  368.             dump(pos,&size,1);
  369.         if (output)
  370.             (void)fwrite((void *)&size,1,1,dest);
  371.         pos=ftell(src);
  372.         (void)fread((void *)buffer,(size_t)size,1,src);
  373.         if (debug)
  374.             dump(pos,buffer,(size_t)size);
  375.         if (output)
  376.             (void)fwrite((void *)buffer,(size_t)size,1,dest);
  377.     } while (!feof(src)&&size>0);
  378. }
  379.  
  380.  
  381. int giftrans(src,dest)
  382. FILE    *src;
  383. FILE    *dest;
  384. {
  385.     unsigned char    buffer[3*256],lsd[7],gct[3*256],gce[5];
  386.     unsigned int    cnt,cols,size,gct_size,gct_delay,gce_present;
  387.     struct entry    *rgbptr;
  388.  
  389.  
  390.     /* Header */
  391.     pos=ftell(src);
  392.     (void)fread((void *)buffer,6,1,src);
  393.     if (strncmp((char *)buffer,"GIF",3)) {
  394.         (void)fprintf(stderr,"No GIF file!\n");
  395.         return(1);
  396.     }
  397.     if (verbose) {
  398.         buffer[6]='\0';
  399.         (void)fprintf(stderr,"Header: \"%s\"\n",buffer);
  400.     }
  401.     if (debug)
  402.         dump(pos,buffer,6);
  403.     if (output) {
  404.         if (!strncmp((char *)buffer,"GIF87a",6))
  405.             buffer[4]='9';
  406.         (void)fwrite((void *)buffer,6,1,dest);
  407.     }
  408.  
  409.     /* Logical Screen Descriptor */
  410.     pos=ftell(src);
  411.     (void)fread((void *)lsd,7,1,src);
  412.     if (verbose) {
  413.         (void)fprintf(stderr,"Logical Screen Descriptor:\n");
  414.         (void)fprintf(stderr,"\tLogical Screen Width: %d pixels\n",readword(lsd));
  415.         (void)fprintf(stderr,"\tLogical Screen Height: %d pixels\n",readword(lsd+2));
  416.         (void)fprintf(stderr,"\tGlobal Color Table Flag: %s\n",readflag(lsd[4]&0x80));
  417.         (void)fprintf(stderr,"\tColor Resolution: %d bits\n",(lsd[4]&0x70>>4)+1);
  418.         if (lsd[4]&0x80) {
  419.             (void)fprintf(stderr,"\tSort Flag: %s\n",readflag(lsd[4]&0x8));
  420.             (void)fprintf(stderr,"\tSize of Global Color Table: %d colors\n",2<<(lsd[4]&0x7));
  421.             (void)fprintf(stderr,"\tBackground Color Index: %d\n",lsd[5]);
  422.         }
  423.         if (lsd[6])
  424.             (void)fprintf(stderr,"\tPixel Aspect Ratio: %d (Aspect Ratio %f)\n",lsd[6],((double)lsd[6]+15)/64);
  425.     }
  426.     if (debug)
  427.         dump(pos,lsd,7);
  428.  
  429.     /* Global Color Table */
  430.     gct_delay=FALSE;
  431.     if (lsd[4]&0x80) {
  432.         gct_size=2<<(lsd[4]&0x7);
  433.         pos=ftell(src);
  434.         (void)fread((void *)gct,gct_size,3,src);
  435.         if (go.index==RGB)
  436.             for(cnt=0;cnt<gct_size&&go.index==RGB;cnt++)
  437.                 if (gct[3*cnt]==go.red&&gct[3*cnt+1]==go.green&&gct[3*cnt+2]==go.blue)
  438.                     go.index=cnt;
  439.         if (go.index>=0) {
  440.             if (gn.index>=0) {
  441.                 gn.red=gct[3*gn.index];
  442.                 gn.green=gct[3*gn.index+1];
  443.                 gn.blue=gct[3*gn.index+2];
  444.             }
  445.             gct[3*go.index]=gn.red;
  446.             gct[3*go.index+1]=gn.green;
  447.             gct[3*go.index+2]=gn.blue;
  448.         }
  449.         if (bc.index==RGB)
  450.             for(cnt=0;cnt<gct_size&&bc.index==RGB;cnt++)
  451.                 if (gct[3*cnt]==bc.red&&gct[3*cnt+1]==bc.green&&gct[3*cnt+2]==bc.blue)
  452.                     bc.index=cnt;
  453.         if (bc.index>=0)
  454.             lsd[5]=bc.index;
  455.         if (tc.index==RGB)
  456.             for(cnt=0;cnt<gct_size&&tc.index==RGB;cnt++)
  457.                 if (gct[3*cnt]==tc.red&&gct[3*cnt+1]==tc.green&&gct[3*cnt+2]==tc.blue)
  458.                     tc.index=cnt;
  459.         if (tc.index==OTHER)
  460.             tc.index=lsd[5];
  461.         if (tn.index>=0) {
  462.             tn.red=gct[3*tn.index];
  463.             tn.green=gct[3*tn.index+1];
  464.             tn.blue=gct[3*tn.index+2];
  465.         }
  466.         if (tn.index!=NONE)
  467.             gct_delay=TRUE;
  468.     }
  469.     if (output)
  470.         (void)fwrite((void *)lsd,7,1,dest);
  471.     if (lsd[4]&0x80) {
  472.         if (list||verbose) {
  473.             (void)fprintf(stderr,"Global Color Table:\n");
  474.             for(cnt=0;cnt<gct_size;cnt++) {
  475.                 (void)fprintf(stderr,"\tColor %d: Red %d, Green %d, Blue %d",cnt,gct[3*cnt],gct[3*cnt+1],gct[3*cnt+2]);
  476.                 (void)fprintf(stderr,", #%02x%02x%02x",gct[3*cnt],gct[3*cnt+1],gct[3*cnt+2]);
  477.                 for (rgbptr=root,cols=0;rgbptr;rgbptr=rgbptr->next)
  478.                     if (rgbptr->red==gct[3*cnt]&&rgbptr->green==gct[3*cnt+1]&&rgbptr->blue==gct[3*cnt+2])
  479.                         (void)fprintf(stderr,"%s%s",cols++?", ":" (",rgbptr->name);
  480.                 (void)fprintf(stderr,"%s\n",cols?")":"");
  481.             }
  482.         }
  483.         if (debug)
  484.             dump(pos,gct,gct_size*3);
  485.         if (output&&(!gct_delay))
  486.             (void)fwrite((void *)gct,gct_size,3,dest);
  487.     }
  488.  
  489.     gce_present=FALSE;
  490.     do {
  491.         pos=ftell(src);
  492.         (void)fread((void *)buffer,1,1,src);
  493.         switch (buffer[0]) {
  494.         case 0x2c:    /* Image Descriptor */
  495.             if (verbose)
  496.                 (void)fprintf(stderr,"Image Descriptor:\n");
  497.             (void)fread((void *)(buffer+1),9,1,src);
  498.             /* Write Graphic Control Extension */
  499.             if (tc.index>=0||gce_present) {
  500.                 if (!gce_present) {
  501.                     gce[0]=0;
  502.                     gce[1]=0;
  503.                     gce[2]=0;
  504.                 }
  505.                 if (tc.index>=0) {
  506.                     gce[0]|=0x01;    /* Set Transparent Color Flag */
  507.                     gce[3]=tc.index;    /* Set Transparent Color Index */
  508.                 }
  509.                 else if (gce[0]&0x01)
  510.                     tc.index=gce[3];    /* Remember Transparent Color Index */
  511.                 gce[4]=0;
  512.                 if (tc.index>=0&&(!(buffer[8]&0x80))) { /* Transparent Color Flag set and no Local Color Table */
  513.                     gct[3*tc.index]=tn.red;
  514.                     gct[3*tc.index+1]=tn.green;
  515.                     gct[3*tc.index+2]=tn.blue;
  516.                 }
  517.                 if (output&&gct_delay) {
  518.                     (void)fwrite((void *)gct,gct_size,3,dest);
  519.                     gct_delay=FALSE;
  520.                 }
  521.                 if (output) {
  522.                     (void)fputs("\041\371\004",dest);
  523.                     (void)fwrite((void *)gce,5,1,dest);
  524.                 }
  525.             }
  526.             if (output&&gct_delay) {
  527.                 if (verbose)
  528.                     (void)fprintf(stderr,"Warning: Global Color Table has not been modified as no Transparent Color Index has been set\n");
  529.                 (void)fwrite((void *)gct,gct_size,3,dest);
  530.                 gct_delay=FALSE;
  531.             }
  532.             /* Write Image Descriptor */
  533.             if (verbose) {
  534.                 (void)fprintf(stderr,"\tImage Left Position: %d pixels\n",readword(buffer+1));
  535.                 (void)fprintf(stderr,"\tImage Top Position: %d pixels\n",readword(buffer+3));
  536.                 (void)fprintf(stderr,"\tImage Width: %d pixels\n",readword(buffer+5));
  537.                 (void)fprintf(stderr,"\tImage Height: %d pixels\n",readword(buffer+7));
  538.                 (void)fprintf(stderr,"\tLocal Color Table Flag: %s\n",readflag(buffer[9]&0x80));
  539.                 (void)fprintf(stderr,"\tInterlace Flag: %s\n",readflag(buffer[9]&0x40));
  540.                 if (buffer[9]&0x80) {
  541.                     (void)fprintf(stderr,"\tSort Flag: %s\n",readflag(buffer[9]&0x20));
  542.                     (void)fprintf(stderr,"\tSize of Global Color Table: %d colors\n",2<<(buffer[9]&0x7));
  543.                 }
  544.             }
  545.             if (debug)
  546.                 dump(pos,buffer,10);
  547.             if (output)
  548.                 (void)fwrite((void *)buffer,10,1,dest);
  549.             /* Local Color Table */
  550.             if (buffer[8]&0x80) {
  551.                 size=2<<(buffer[8]&0x7);
  552.                 pos=ftell(src);
  553.                 (void)fread((void *)buffer,size,3,src);
  554.                 if (verbose) {
  555.                     (void)fprintf(stderr,"Local Color Table:\n");
  556.                     for(cnt=0;cnt<size;cnt++)
  557.                         (void)fprintf(stderr,"\tColor %d: Red %d, Green %d, Blue %d\n",cnt,buffer[3*cnt],buffer[3*cnt+1],buffer[3*cnt+2]);
  558.                 }
  559.                 if (tc.index>=0) { /* Transparent Color Flag set */
  560.                     buffer[3*tc.index]=tn.red;
  561.                     buffer[3*tc.index+1]=tn.green;
  562.                     buffer[3*tc.index+2]=tn.blue;
  563.                 }
  564.                 if (debug)
  565.                     dump(pos,buffer,size*3);
  566.                 if (output)
  567.                     (void)fwrite((void *)buffer,size,3,dest);
  568.             }
  569.             /* Table Based Image Data */
  570.             pos=ftell(src);
  571.             (void)fread((void *)buffer,1,1,src);
  572.             if (verbose) {
  573.                 (void)fprintf(stderr,"Table Based Image Data:\n");
  574.                 (void)fprintf(stderr,"\tLZW Minimum Code Size: 0x%02x\n",buffer[0]);
  575.             }
  576.             if (debug)
  577.                 dump(pos,buffer,1);
  578.             if (output)
  579.                 (void)fwrite((void *)buffer,1,1,dest);
  580.             transdata(src,dest);
  581.             gce_present=FALSE;
  582.             break;
  583.         case 0x3b:    /* Trailer */
  584.             if (verbose)
  585.                 (void)fprintf(stderr,"Trailer\n");
  586.             if (debug)
  587.                 dump(pos,buffer,1);
  588.             if (comment&&*comment&&output) {
  589.                 (void)fputs("\041\376",dest);
  590.                 writedata(dest,(unsigned char *)comment,strlen(comment));
  591.             }
  592.             if (output)
  593.                 (void)fwrite((void *)buffer,1,1,dest);
  594.             break;
  595.         case 0x21:    /* Extension */
  596.             (void)fread((void *)(buffer+1),1,1,src);
  597.             switch (buffer[1]) {
  598.             case 0x01:    /* Plain Text Extension */
  599.                 if (output&&gct_delay) {
  600.                     if (verbose)
  601.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Plain Text Extension\n");
  602.                     (void)fwrite((void *)gct,gct_size,3,dest);
  603.                     gct_delay=FALSE;
  604.                 }
  605.                 if (verbose)
  606.                     (void)fprintf(stderr,"Plain Text Extension\n");
  607.                 if (debug)
  608.                     dump(pos,buffer,2);
  609.                 if (output)
  610.                     (void)fwrite((void *)buffer,2,1,dest);
  611.                 transblock(src,dest);
  612.                 transdata(src,dest);
  613.                 break;
  614.             case 0xf9:    /* Graphic Control Extension */
  615.                 if (verbose)
  616.                     (void)fprintf(stderr,"Graphic Control Extension:\n");
  617.                 (void)fread((void *)(buffer+2),1,1,src);
  618.                 size=buffer[2];
  619.                 (void)fread((void *)gce,size,1,src);
  620.                 if (verbose) {
  621.                     (void)fprintf(stderr,"\tDisposal Method: %d ",gce[0]&0x1c>>2);
  622.                     switch (gce[0]&0x1c>>2) {
  623.                     case 0:
  624.                         (void)fprintf(stderr,"(no disposal specified)\n");
  625.                         break;
  626.                     case 1:
  627.                         (void)fprintf(stderr,"(do not dispose)\n");
  628.                         break;
  629.                     case 2:
  630.                         (void)fprintf(stderr,"(restore to background color)\n");
  631.                         break;
  632.                     case 3:
  633.                         (void)fprintf(stderr,"(restore to previous)\n");
  634.                         break;
  635.                     default:
  636.                         (void)fprintf(stderr,"(to be defined)\n");
  637.                     }
  638.                     (void)fprintf(stderr,"\tUser Input Flag: %s\n",readflag(gce[0]&0x2));
  639.                     (void)fprintf(stderr,"\tTransparent Color Flag: %s\n",readflag(gce[0]&0x1));
  640.                     (void)fprintf(stderr,"\tDelay Time: %d\n",readword(gce+1));
  641.                     if (gce[0]&0x1)
  642.                         (void)fprintf(stderr,"\tTransparent Color Index: %d\n",gce[3]);
  643.                 }
  644.                 if (debug) {
  645.                     dump(pos,buffer,3);
  646.                     dump(pos+3,gce,size);
  647.                 }
  648.                 pos=ftell(src);
  649.                 (void)fread((void *)buffer,1,1,src);
  650.                 if (debug)
  651.                     dump(pos,buffer,1);
  652.                 gce_present=TRUE;
  653.                 break;
  654.             case 0xfe:    /* Comment Extension */
  655.                 if (verbose)
  656.                 {
  657.                     (void)fprintf(stderr,"Comment Extension\n");
  658.                     dumpcomment(src);
  659.                 }
  660.                 if (debug)
  661.                     dump(pos,buffer,2);
  662.                 if (skipcomment)
  663.                     skipdata(src);
  664.                 else {
  665.                     if (output&&gct_delay) {
  666.                         if (verbose)
  667.                             (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Comment Extension\n");
  668.                         (void)fwrite((void *)gct,gct_size,3,dest);
  669.                         gct_delay=FALSE;
  670.                     }
  671.                     if (output)
  672.                         (void)fwrite((void *)buffer,2,1,dest);
  673.                     transdata(src,dest);
  674.                 }
  675.                 break;
  676.             case 0xff:    /* Application Extension */
  677.                 if (output&&gct_delay) {
  678.                     if (verbose)
  679.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Application Extension\n");
  680.                     (void)fwrite((void *)gct,gct_size,3,dest);
  681.                     gct_delay=FALSE;
  682.                 }
  683.                 if (verbose)
  684.                     (void)fprintf(stderr,"Application Extension\n");
  685.                 if (debug)
  686.                     dump(pos,buffer,2);
  687.                 if (output)
  688.                     (void)fwrite((void *)buffer,2,1,dest);
  689.                 transblock(src,dest);
  690.                 transdata(src,dest);
  691.                 break;
  692.             default:
  693.                 if (output&&gct_delay) {
  694.                     if (verbose)
  695.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to an unknown Extension\n");
  696.                     (void)fwrite((void *)gct,gct_size,3,dest);
  697.                     gct_delay=FALSE;
  698.                 }
  699.                 if (verbose)
  700.                     (void)fprintf(stderr,"Unknown label: 0x%02x\n",buffer[1]);
  701.                 if (debug)
  702.                     dump(pos,buffer,2);
  703.                 if (output)
  704.                     (void)fwrite((void *)buffer,2,1,dest);
  705.                 transblock(src,dest);
  706.                 transdata(src,dest);
  707.                 break;
  708.             }
  709.             break;
  710.         default:
  711.             (void)fprintf(stderr,"0x%08lx: Unknown extension 0x%02x!\n",ftell(src)-1,buffer[0]);
  712.             if (debug)
  713.                 dump(pos,buffer,1);
  714.             return(1);
  715.         }
  716.     } while (buffer[0]!=0x3b&&!feof(src));
  717.     return(buffer[0]==0x3b?SUCCESS:FAILURE);
  718. }
  719.  
  720.  
  721.  
  722. int getindex(c,arg)
  723. struct color    *c;
  724. char    *arg;
  725. {
  726.     struct entry    *ptr;
  727.  
  728.     if ('0'<=*arg&&*arg<='9')
  729.         c->index=atoi(arg);
  730.     else if (*arg=='#') {
  731.         if (strlen(arg)==4) {
  732.             c->index=RGB;
  733.             c->red=hex(arg[1])<<4;
  734.             c->green=hex(arg[2])<<4;
  735.             c->blue=hex(arg[3])<<4;
  736.         }
  737.         else if (strlen(arg)==7) {
  738.             c->index=RGB;
  739.             c->red=(hex(arg[1])<<4)+hex(arg[2]);
  740.             c->green=(hex(arg[3])<<4)+hex(arg[4]);
  741.             c->blue=(hex(arg[5])<<4)+hex(arg[6]);
  742.         }
  743.         else {
  744.             (void)fprintf(stderr,"%s: illegal color specification: %s\n",image,arg);
  745.             return(FAILURE);
  746.         }
  747.     }
  748.     else {
  749.         for (ptr=root;ptr&&c->index!=RGB;ptr=ptr->next)
  750.             if (!strcmp(ptr->name,arg)) {
  751.                 c->index=RGB;
  752.                 c->red=ptr->red;
  753.                 c->green=ptr->green;
  754.                 c->blue=ptr->blue;
  755.             }
  756.         if (c->index!=RGB) {
  757.             (void)fprintf(stderr,"%s: no such color: %s\n",image,arg);
  758.             return(FAILURE);
  759.         }
  760.     }
  761.     return(SUCCESS);
  762. }
  763.  
  764.  
  765.  
  766. void usage()
  767. {
  768.     (void)fprintf(stderr,"Usage: %s [-t color|-T] [-B color] [-b color] [-g oldcolor=newcolor] [-c comment|-C] [-l|-L|-V] [-o filename] [-e filename] [filename]\n",image);
  769.     (void)fprintf(stderr,"Convert any GIF file into a GIF89a, with the folloing changes possible:\n");
  770.     (void)fprintf(stderr,"-t Specify the transparent color\n");
  771.     (void)fprintf(stderr,"-T Index of the transparent color is the background color index\n");
  772.     (void)fprintf(stderr,"-B Specify the transparent color's new value\n");
  773.     (void)fprintf(stderr,"-b Specify the background color\n");
  774.     (void)fprintf(stderr,"-g Change a color in the global color table\n");
  775.     (void)fprintf(stderr,"-c Add a comment\n");
  776.     (void)fprintf(stderr,"-C Remove old comment\n");
  777.     (void)fprintf(stderr,"-l Only list the color table\n");
  778.     (void)fprintf(stderr,"-L Verbose output of GIFs contents\n");
  779.     (void)fprintf(stderr,"-V Verbose output while converting\n");
  780.     (void)fprintf(stderr,"-o Redirect stdout to a file\n");
  781.     (void)fprintf(stderr,"-e Redirect stderr to a file\n");
  782.     if (*rgb)
  783.         (void)fprintf(stderr,"Colors may be specified as index, as rgb.txt entry or in the #rrggbb form.\n");
  784.     else
  785.         (void)fprintf(stderr,"Colors may be specified as index or in the #rrggbb form.\n");
  786.     exit(1);
  787. }
  788.  
  789.  
  790. int main(argc,argv)
  791. int    argc;
  792. char    *argv[];
  793. {
  794.     int        c;
  795.     extern char    *optarg;
  796.     extern int    optind;
  797.     char        error[2*MAXPATHLEN+14],line[BUFSIZ],*ptr,*nptr,*oname,*ename;
  798.     struct entry    **next;
  799.     FILE        *src;
  800.     int        stat;
  801.  
  802. #ifdef OS2
  803.     ptr=getenv("XFILES");
  804.     if (ptr) {
  805.         rgb=(char *)malloc(strlen(ptr)+strlen(rgbtxt)+2);
  806.         (void)strcpy(rgb,ptr);
  807.         (void)strcat(rgb,"\\");
  808.         (void)strcat(rgb,rgbtxt);
  809.     }
  810. #endif /* OS2 */
  811.  
  812.     image=argv[0];
  813.     root=NULL;
  814.     if (*rgb)
  815.         if ((src=fopen(rgb,"r"))!=NULL) {
  816.             next= &root;
  817.             while (fgets(line,sizeof(line),src)) {
  818.                 *next=(struct entry *)malloc(sizeof(struct entry));
  819.                 for (ptr=line;strchr(" \t",*ptr);ptr++);
  820.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  821.                 *ptr++='\0';
  822.                 (*next)->red=atoi(nptr);
  823.                 for (;strchr(" \t",*ptr);ptr++);
  824.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  825.                 *ptr++='\0';
  826.                 (*next)->green=atoi(nptr);
  827.                 for (;strchr(" \t",*ptr);ptr++);
  828.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  829.                 *ptr++='\0';
  830.                 (*next)->blue=atoi(nptr);
  831.                 for (;strchr(" \t",*ptr);ptr++);
  832.                 nptr=ptr;
  833.                 for (ptr=strchr(ptr,'\0');ptr>nptr&&strchr(" \t\r\n",*(ptr-1));ptr--);
  834.                 *ptr='\0';
  835.                 (void)strcpy((*next)->name=(char *)malloc(strlen(nptr)+1),nptr);
  836.                 (*next)->next=NULL;
  837.                 next= &(*next)->next;
  838.             }
  839.             (void)fclose(src);
  840.         }
  841.         else {
  842. #ifndef OS2_OR_MSDOS
  843.             (void)sprintf(error,"%s: cannot open %s",image,rgb);
  844.             perror(error);
  845.             return(FAILURE);
  846. #else /* OS2_OR_MSDOS */
  847.             *rgb='\0';
  848. #endif
  849.         }
  850.  
  851.     bc.index=NONE;
  852.     tc.index=NONE;
  853.     tn.index=NONE;
  854.     go.index=NONE;
  855.     gn.index=NONE;
  856.     comment=NULL;
  857.     skipcomment=FALSE;
  858.     verbose=FALSE;
  859.     output=TRUE;
  860.     debug=FALSE;
  861.     oname=NULL;
  862.     ename=NULL;
  863.     while ((c=getopt(argc,argv,"t:TB:b:g:c:ClLVDo:e:vh?")) != EOF)
  864.         switch ((char)c) {
  865.         case 'b':
  866.             if (getindex(&bc,optarg))
  867.                 return(FAILURE);
  868.             break;
  869.         case 't':
  870.             if (getindex(&tc,optarg))
  871.                 return(FAILURE);
  872.             break;
  873.         case 'T':
  874.             tc.index=OTHER;
  875.             break;
  876.         case 'B':
  877.             if (getindex(&tn,optarg))
  878.                 return(FAILURE);
  879.             break;
  880.         case 'g':
  881.             if ((ptr=strchr(optarg,'='))!=NULL) {
  882.                 *ptr++='\0';
  883.                 if (getindex(&go,optarg))
  884.                     return(FAILURE);
  885.                 if (getindex(&gn,ptr))
  886.                     return(FAILURE);
  887.             }
  888.             else
  889.                 usage();
  890.             break;
  891.         case 'c':
  892.             comment=optarg;
  893.             break;
  894.         case 'C':
  895.             skipcomment=TRUE;
  896.             break;
  897.         case 'l':
  898.             list=TRUE;
  899.             output=FALSE;
  900.             break;
  901.         case 'L':
  902.             verbose=TRUE;
  903.             output=FALSE;
  904.             break;
  905.         case 'V':
  906.             verbose=TRUE;
  907.             break;
  908.         case 'D':
  909.             debug=TRUE;
  910.             break;
  911.         case 'o':
  912.             oname=optarg;
  913.             break;
  914.         case 'e':
  915.             ename=optarg;
  916.             break;
  917.         case 'v':
  918.             (void)fprintf(stderr,"%s\n",sccsid+4);
  919.             (void)fprintf(stderr,"%s\n",copyright+4);
  920.             return(0);
  921.         case 'h':
  922.             (void)fprintf(stderr,"%s\n",sccsid+4);
  923.             (void)fprintf(stderr,"%s\n",copyright+4);
  924.         case '?':
  925.             usage();
  926.         }
  927.     if (optind+1<argc||(bc.index==NONE&&tc.index==NONE&&tn.index==NONE&&gn.index==NONE&&comment==NULL&&!skipcomment&&!list&&!verbose))
  928.         usage();
  929.  
  930.     if (oname&&freopen(oname,"wb",stdout)==NULL) {
  931.         (void)sprintf(error,"%s: cannot open %s",image,oname);
  932.         perror(error);
  933.         return(FAILURE);
  934.     }
  935.  
  936.     if (ename&&freopen(ename,"wb",stderr)==NULL) {
  937.         (void)sprintf(error,"%s: cannot open %s",image,ename);
  938.         perror(error);
  939.         return(FAILURE);
  940.     }
  941.  
  942. #ifdef OS2_OR_MSDOS
  943. #ifdef MSDOS
  944.     if(oname==NULL&&(stdout->flags&_F_TERM)==0&&setmode(fileno(stdout),O_BINARY)!=0) {
  945. #endif /* MSDOS */
  946. #ifdef OS2
  947.     if(oname==NULL&&!freopen("", "wb", stdout)) {
  948. #endif /* OS2 */
  949.         (void)fprintf(stderr,"%s: can't set stdout's mode to binary\n",image);
  950.         exit(2);
  951.     }
  952. #ifdef MSDOS
  953.     if(optind==argc&&(stdin->flags&_F_TERM)==0&&setmode(fileno(stdin),O_BINARY)) {
  954. #endif /* MSDOS */
  955. #ifdef OS2
  956.     if(optind==argc&&!freopen("", "rb", stdin)) {
  957. #endif /* OS2 */
  958.         (void)fprintf(stderr,"%s: can't set stdin's mode to binary\n",image);
  959.         exit(2);
  960.     }
  961. #endif /* OS2_OR_MSDOS */
  962.  
  963.     if (optind<argc)
  964.         if (strcmp(argv[optind],"-"))
  965.             if ((src=fopen(argv[optind],"rb"))!=NULL) {
  966.                 stat=giftrans(src,stdout);
  967.                 (void)fclose(src);
  968.             }
  969.             else {
  970.                 (void)sprintf(error,"%s: cannot open %s",image,argv[optind]);
  971.                 perror(error);
  972.                 return(FAILURE);
  973.             }
  974.         else
  975.             stat=giftrans(stdin,stdout);
  976.     else
  977.         stat=giftrans(stdin,stdout);
  978.  
  979.     (void)fclose(stdout);
  980.     (void)fclose(stderr);
  981.     return(stat);
  982. }
  983.